﻿using LeagueSharp;
using LeagueSharp.Common;
using SharpDX;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Color = 

namespace OneKeyToWin_AIO_Sebby.Core {
	public static class COrbwalker {

		public delegate void AfterAttackEvenH(AttackableUnit unit, AttackableUnit target);

		public delegate void BeforeAttackEvenH(BeforeAttackEventArgs args);

		public delegate void OnAttackEvenH(AttackableUnit unit, AttackableUnit target);

		public delegate void OnNonKillableMinionH(AttackableUnit minion);

		public delegate void OnTargetChangeH(AttackableUnit oldTarget, AttackableUnit newTarget);

		public enum OrbwalkingMode {
			LastHit,
			Mixed,
			LaneClear,
			Combo,
			None
		}

		//Spells that reset the attack timer.
		private static readonly string[] AttackResets =
		{
			"dariusnoxiantacticsonh", "fioraflurry", "garenq",
			"hecarimrapidslash", "jaxempowertwo", "jaycehypercharge", "leonashieldofdaybreak", "luciane", "lucianq",
			"monkeykingdoubleattack", "mordekaisermaceofspades", "nasusq", "nautiluspiercinggaze", "netherblade",
			"parley", "poppydevastatingblow", "powerfist", "renektonpreexecute", "rengarq", "shyvanadoubleattack",
			"sivirw", "takedown", "talonnoxiandiplomacy", "trundletrollsmash", "vaynetumble", "vie", "volibearq",
			"xenzhaocombotarget", "yorickspectral", "reksaiq"
		};

		//Spells that are not attacks even if they have the "attack" word in their name.
		private static readonly string[] NoAttacks =
		{
			"jarvanivcataclysmattack", "monkeykingdoubleattack",
			"shyvanadoubleattack", "shyvanadoubleattackdragon", "zyragraspingplantattack", "zyragraspingplantattack2",
			"zyragraspingplantattackfire", "zyragraspingplantattack2fire", "viktorpowertransfer", "sivirwattackbounce"
		};

		//Spells that are attacks even if they dont have the "attack" word in their name.
		private static readonly string[] Attacks =
		{
			"caitlynheadshotmissile", "frostarrow", "garenslash2",
			"kennenmegaproc", "lucianpassiveattack", "masteryidoublestrike", "quinnwenhanced", "renektonexecute",
			"renektonsuperexecute", "rengarnewpassivebuffdash", "trundleq", "xenzhaothrust", "xenzhaothrust2",
			"xenzhaothrust3", "viktorqbuff"
		};

		// Champs whose auto attacks can't be cancelled
		private static readonly string[] NoCancelChamps = { "Kalista" };
		public static int LastAATick;
		public static bool Attack = true;
		public static bool DisableNextAttack;
		public static bool Move = true;
		public static int LastMoveCommandT;
		public static Vector3 LastMoveCommandPosition = Vector3.Zero;
		private static AttackableUnit _lastTarget;
		private static readonly Obj_AI_Hero Player;
		private static int _delay;
		private static float _minDistance = 300;
		private static bool _missileLaunched;
		private static readonly Random _random = new Random(DateTime.Now.Millisecond);

		static COrbwalker() {
			Player = ObjectManager.Player;
			Obj_AI_Base.OnProcessSpellCast += OnProcessSpell;
			MissileClient.OnCreate += MissileClient_OnCreate;
			Spellbook.OnStopCast += SpellbookOnStopCast;
		}

		/// <summary>
		///     This event is fired before the player auto attacks.
		/// </summary>
		public static event BeforeAttackEvenH BeforeAttack;

		/// <summary>
		///     This event is fired when a unit is about to auto-attack another unit.
		/// </summary>
		public static event OnAttackEvenH OnAttack;

		/// <summary>
		///     This event is fired after a unit finishes auto-attacking another unit (Only works with player for now).
		/// </summary>
		public static event AfterAttackEvenH AfterAttack;

		/// <summary>
		///     Gets called on target changes
		/// </summary>
		public static event OnTargetChangeH OnTargetChange;

		//  <summary>
		//      Gets called if you can't kill a minion with auto attacks
		//  </summary>
		public static event OnNonKillableMinionH OnNonKillableMinion;

		private static void FireBeforeAttack(AttackableUnit target) {
			if (BeforeAttack != null)
			{
				BeforeAttack(new BeforeAttackEventArgs { Target = target });
			}
			else
			{
				DisableNextAttack = false;
			}
		}

		private static void FireOnAttack(AttackableUnit unit, AttackableUnit target) {
			if (OnAttack != null)
			{
				OnAttack(unit, target);
			}
		}

		private static void FireAfterAttack(AttackableUnit unit, AttackableUnit target) {
			if (AfterAttack != null && target.IsValidTarget())
			{
				AfterAttack(unit, target);
			}
		}

		private static void FireOnTargetSwitch(AttackableUnit newTarget) {
			if (OnTargetChange != null && (!_lastTarget.IsValidTarget() || _lastTarget != newTarget))
			{
				OnTargetChange(_lastTarget, newTarget);
			}
		}

		private static void FireOnNonKillableMinion(AttackableUnit minion) {
			if (OnNonKillableMinion != null)
			{
				OnNonKillableMinion(minion);
			}
		}

		/// <summary>
		///     Returns true if the spellname resets the attack timer.
		/// </summary>
		public static bool IsAutoAttackReset(string name) {
			return AttackResets.Contains(name.ToLower());
		}

		/// <summary>
		///     Returns true if the unit is melee
		/// </summary>
		public static bool IsMelee(this Obj_AI_Base unit) {
			return unit.CombatType == GameObjectCombatType.Melee;
		}

		/// <summary>
		///     Returns true if the spellname is an auto-attack.
		/// </summary>
		public static bool IsAutoAttack(string name) {
			return (name.ToLower().Contains("attack") && !NoAttacks.Contains(name.ToLower())) ||
				   Attacks.Contains(name.ToLower());
		}

		/// <summary>
		///     Returns the auto-attack range.
		/// </summary>
		public static float GetRealAutoAttackRange(AttackableUnit target) {
			var result = Player.AttackRange + Player.BoundingRadius - 15;
			if (target.IsValidTarget())
			{
				return result + target.BoundingRadius;
			}
			return result;
		}

		/// <summary>
		///     Returns true if the target is in auto-attack range.
		/// </summary>
		public static bool InAutoAttackRange(AttackableUnit target) {
			if (!target.IsValidTarget())
			{
				return false;
			}
			var myRange = GetRealAutoAttackRange(target);
			return
				Vector2.DistanceSquared(
					(target is Obj_AI_Base) ? ((Obj_AI_Base)target).ServerPosition.To2D() : target.Position.To2D(),
					Player.ServerPosition.To2D()) <= myRange * myRange;
		}

		/// <summary>
		///     Returns player auto-attack missile speed.
		/// </summary>
		public static float GetMyProjectileSpeed() {
			return IsMelee(Player) || Player.ChampionName == "Azir" ? float.MaxValue : Player.BasicAttack.MissileSpeed;
		}

		/// <summary>
		///     Returns if the player's auto-attack is ready.漏洞问题
		/// </summary>
		public static bool CanAttack() {
			if (true)
			{
				return LeagueSharp.Common.Utils.GameTimeTickCount + Game.Ping / 2 >=
					   LastAATick + Player.AttackDelay * 1000 - 150 && Attack;
			}
			return LeagueSharp.Common.Utils.GameTimeTickCount + Game.Ping / 2 >=
					   LastAATick + Player.AttackDelay * 1000 && Attack;
		}

		/// <summary>
		///     Returns true if moving won't cancel the auto-attack.
		/// </summary>
		public static bool CanMove(float extraWindup) {
			if (!Move)
			{
				return false;
			}

			if (_missileLaunched && Orbwalker.MissileCheck)
			{
				return true;
			}

			return NoCancelChamps.Contains(Player.ChampionName) || (LeagueSharp.Common.Utils.GameTimeTickCount + Game.Ping / 2 >= LastAATick + Player.AttackCastDelay * 1000 + extraWindup);
		}

		public static void SetMovementDelay(int delay) {
			_delay = delay;
		}

		public static void SetMinimumOrbwalkDistance(float d) {
			_minDistance = d;
		}

		public static float GetLastMoveTime() {
			return LastMoveCommandT;
		}

		public static Vector3 GetLastMovePosition() {
			return LastMoveCommandPosition;
		}

		public static void MoveTo(Vector3 position,
			float holdAreaRadius = 0,
			bool overrideTimer = false,
			bool useFixedDistance = true,
			bool randomizeMinDistance = true) {
			if (LeagueSharp.Common.Utils.GameTimeTickCount - LastMoveCommandT < _delay + _random.Next(-10, 10) && !overrideTimer)
			{
				return;
			}

			LastMoveCommandT = LeagueSharp.Common.Utils.GameTimeTickCount;

			if (Player.ServerPosition.Distance(position, true) < holdAreaRadius * holdAreaRadius)
			{
				if (Player.Path.Count() > 1)
				{
					Player.IssueOrder((GameObjectOrder)10, Player.ServerPosition);
					Player.IssueOrder(GameObjectOrder.HoldPosition, Player.ServerPosition);
					LastMoveCommandPosition = Player.ServerPosition;
				}
				return;
			}

			var point = position;
			if (useFixedDistance)
			{
				point = Player.ServerPosition +
						(randomizeMinDistance ? (_random.NextFloat(0.6f, 1) + 0.2f) * _minDistance : _minDistance) *
						(position.To2D() - Player.ServerPosition.To2D()).Normalized().To3D();
			}
			else
			{
				if (randomizeMinDistance)
				{
					point = Player.ServerPosition +
							(_random.NextFloat(0.6f, 1) + 0.2f) * _minDistance *
							(position.To2D() - Player.ServerPosition.To2D()).Normalized().To3D();
				}
				else if (Player.ServerPosition.Distance(position) > _minDistance)
				{
					point = Player.ServerPosition +
							_minDistance * (position.To2D() - Player.ServerPosition.To2D()).Normalized().To3D();
				}
			}

			Player.IssueOrder(GameObjectOrder.MoveTo, point);
			LastMoveCommandPosition = point;
		}

		/// <summary>
		///     Orbwalk a target while moving to Position.
		/// </summary>
		public static void Orbwalk(AttackableUnit target,
			Vector3 position,
			float extraWindup = 90,
			float holdAreaRadius = 0,
			bool useFixedDistance = true,
			bool randomizeMinDistance = true) {
			try
			{
				if (target.IsValidTarget() && CanAttack())
				{
					DisableNextAttack = false;
					FireBeforeAttack(target);

					if (!DisableNextAttack)
					{
						if (!NoCancelChamps.Contains(Player.ChampionName))
						{
							LastAATick = LeagueSharp.Common.Utils.GameTimeTickCount + Game.Ping + 100 - (int)(ObjectManager.Player.AttackCastDelay * 1000f);
							_missileLaunched = false;

							var d = GetRealAutoAttackRange(target) - 65;
							if (Player.Distance(target, true) > d * d)
							{
								LastAATick = LeagueSharp.Common.Utils.GameTimeTickCount + Game.Ping + 400 - (int)(ObjectManager.Player.AttackCastDelay * 1000f);
							}
						}
						Player.IssueOrder(GameObjectOrder.AttackUnit, target);
						_lastTarget = target;
						return;
					}
				}

				//if ((!CanAttack() || !target.IsValidTarget()) && CanMove(extraWindup))
				//{
				//	if (Program.Q.IsReady() && Program.Orbwalker.ActiveMode == OrbwalkingMode.Combo && Program.ComboMenu.Item("AAResetQ").GetValue<bool>() && ObjectManager.Player.ManaPercent > Program.ComboMenu.Item("QMinMana").GetValue<Slider>().Value)
				//	{
				//		Program.Q.CastIfHitchanceEquals(target as Obj_AI_Base, HitChance.Medium);
				//	}
				//	MoveTo(position, holdAreaRadius, false, useFixedDistance, randomizeMinDistance);
				//}
			}
			catch (Exception e)
			{
				Console.WriteLine(e.ToString());
			}
		}

		/// <summary>
		///     Resets the Auto-Attack timer.
		/// </summary>
		public static void ResetAutoAttackTimer() {
			LastAATick = 0;
		}

		private static void SpellbookOnStopCast(Spellbook spellbook, SpellbookStopCastEventArgs args) {
			if (spellbook.Owner.IsValid && spellbook.Owner.IsMe && args.DestroyMissile && args.StopAnimation)
			{
				ResetAutoAttackTimer();
			}
		}

		private static void MissileClient_OnCreate(GameObject sender, EventArgs args) {
			var missile = sender as MissileClient;
			if (missile != null && missile.SpellCaster.IsMe && IsAutoAttack(missile.SData.Name))
			{
				_missileLaunched = true;
			}
		}

		private static void OnProcessSpell(Obj_AI_Base unit, GameObjectProcessSpellCastEventArgs Spell) {
			try
			{
				var spellName = Spell.SData.Name;

				if (IsAutoAttackReset(spellName) && unit.IsMe)
				{
					Utility.DelayAction.Add(250, ResetAutoAttackTimer);
				}

				if (!IsAutoAttack(spellName))
				{
					return;
				}

				if (unit.IsMe &&
					(Spell.Target is Obj_AI_Base || Spell.Target is Obj_BarracksDampener || Spell.Target is Obj_HQ))
				{
					LastAATick = LeagueSharp.Common.Utils.GameTimeTickCount - Game.Ping / 2;
					_missileLaunched = false;

					if (Spell.Target is Obj_AI_Base)
					{
						var target = (Obj_AI_Base)Spell.Target;
						if (target.IsValid)
						{
							FireOnTargetSwitch(target);
							_lastTarget = target;
						}

						//Trigger it for ranged until the missiles catch normal attacks again!
						Utility.DelayAction.Add(
							(int)(unit.AttackCastDelay * 1000 + 50), () => FireAfterAttack(unit, _lastTarget));
					}
				}

				FireOnAttack(unit, _lastTarget);
			}
			catch (Exception e)
			{
				Console.WriteLine(e);
			}
		}

		public class BeforeAttackEventArgs {
			private bool _process = true;
			public AttackableUnit Target;
			public Obj_AI_Base Unit = ObjectManager.Player;

			public bool Process {
				get { return _process; }
				set {
					DisableNextAttack = !value;
					_process = value;
				}
			}
		}

		/// <summary>
		///     This class allows you to add an instance of "Orbwalker" to your assembly in order to control the orbwalking in an
		///     easy way.
		/// </summary>
		public class Orbwalker {
			private const float LaneClearWaitTimeMod = 2f;
			private static Menu _config;
			private readonly Obj_AI_Hero Player;
			private Obj_AI_Base _forcedTarget;
			private OrbwalkingMode _mode = OrbwalkingMode.None;
			private Vector3 _orbwalkingPoint;
			private Obj_AI_Minion _prevMinion;
			public static List<Orbwalker> Instances = new List<Orbwalker>();

			public Orbwalker(Menu attachToMenu) {
				_config = attachToMenu;
				var targetSelector = new Menu("Target Selector", "targetselector");
				TargetSelector.AddToMenu(targetSelector);
				_config.AddSubMenu(targetSelector);

				/* Drawings submenu */
				var drawings = new Menu("Drawings", "drawings");
				drawings.AddItem(
					new MenuItem("AACircle", "AACircle")
						.SetValue(new Circle(true, Color.Gold)));
				drawings.AddItem(
					new MenuItem("AACircle2", "Enemy AA circle")
						.SetValue(new Circle(false, Color.Red)));
				drawings.AddItem(
					new MenuItem("AACircle3", "Target AA circle")
						.SetValue(new Circle(true, Color.Gold)));
				drawings.AddItem(
					new MenuItem("HoldZone", "HoldZone")
						.SetValue(new Circle(false, Color.DarkRed)));
				_config.AddSubMenu(drawings);

				/* Misc options */
				var misc = new Menu("Misc", "Misc");
				misc.AddItem(
					new MenuItem("HoldPosRadius", "Hold Position Radius").SetValue(new Slider(50, 0, 250)));
				misc.AddItem(new MenuItem("PriorizeFarm", "Priorize farm over harass").SetShared().SetValue(true));
				_config.AddSubMenu(misc);

				/* Missile check */
				_config.AddItem(new MenuItem("MissileCheck", "Use Missile Check").SetValue(false));

				/* Delay sliders */
				_config.AddItem(
					new MenuItem("ExtraWindup", "Extra windup time").SetValue(new Slider(30, 0, 200)));
				_config.AddItem(new MenuItem("FarmDelay", "Farm delay").SetShared().SetValue(new Slider(25, 0, 200)));
				_config.AddItem(
					new MenuItem("MovementDelay", "Movement delay").SetValue(new Slider(100, 50, 250)))
					.ValueChanged += (sender, args) => SetMovementDelay(args.GetNewValue<Slider>().Value);


				/*Load the menu*/
				_config.AddItem(
					new MenuItem("LastHit", "Last hit").SetShared().SetValue(new KeyBind('X', KeyBindType.Press)));

				_config.AddItem(new MenuItem("Farm", "Mixed").SetShared().SetValue(new KeyBind('C', KeyBindType.Press)));

				_config.AddItem(
					new MenuItem("LaneClear", "LaneClear").SetShared().SetValue(new KeyBind('V', KeyBindType.Press)));

				_config.AddItem(
					new MenuItem("Orbwalk", "Combo").SetShared().SetValue(new KeyBind(32, KeyBindType.Press)));

				_delay = _config.Item("MovementDelay").GetValue<Slider>().Value;


				Player = ObjectManager.Player;
				Game.OnUpdate += OnUpdate;
				Drawing.OnDraw += DrawingOnOnDraw;
				Instances.Add(this);
			}

			public virtual bool InAutoAttackRange(AttackableUnit target) {
				return Orbwalking.InAutoAttackRange(target);
			}

			private int FarmDelay {
				get { return _config.Item("FarmDelay").GetValue<Slider>().Value; }
			}

			public static bool MissileCheck {
				get { return _config.Item("MissileCheck").GetValue<bool>(); }
			}

			public OrbwalkingMode ActiveMode {
				get {
					if (_mode != OrbwalkingMode.None)
					{
						return _mode;
					}

					if (_config.Item("Orbwalk").GetValue<KeyBind>().Active)
					{
						return OrbwalkingMode.Combo;
					}

					if (_config.Item("LaneClear").GetValue<KeyBind>().Active)
					{
						return OrbwalkingMode.LaneClear;
					}

					if (_config.Item("Farm").GetValue<KeyBind>().Active)
					{
						return OrbwalkingMode.Mixed;
					}

					if (_config.Item("LastHit").GetValue<KeyBind>().Active)
					{
						return OrbwalkingMode.LastHit;
					}

					return OrbwalkingMode.None;
				}
				set { _mode = value; }
			}

			/// <summary>
			///     Enables or disables the auto-attacks.
			/// </summary>
			public void SetAttack(bool b) {
				Attack = b;
			}

			/// <summary>
			///     Enables or disables the movement.
			/// </summary>
			public void SetMovement(bool b) {
				Move = b;
			}

			/// <summary>
			///     Forces the orbwalker to attack the set target if valid and in range.
			/// </summary>
			public void ForceTarget(Obj_AI_Base target) {
				_forcedTarget = target;
			}

			/// <summary>
			///     Forces the orbwalker to move to that point while orbwalking (Game.CursorPos by default).
			/// </summary>
			public void SetOrbwalkingPoint(Vector3 point) {
				_orbwalkingPoint = point;
			}

			public bool ShouldWait() {
				return
					ObjectManager.Get<Obj_AI_Minion>()
						.Any(
							minion =>
								minion.IsValidTarget() && minion.Team != GameObjectTeam.Neutral &&
								InAutoAttackRange(minion) &&
								HealthPrediction.LaneClearHealthPrediction(
									minion, (int)((Player.AttackDelay * 1000) * LaneClearWaitTimeMod), FarmDelay) <=
								Player.GetAutoAttackDamage(minion));
			}

			public virtual AttackableUnit GetTarget() {
				AttackableUnit result = null;

				if ((ActiveMode == OrbwalkingMode.Mixed || ActiveMode == OrbwalkingMode.LaneClear) &&
					!_config.Item("PriorizeFarm").GetValue<bool>())
				{
					var target = TargetSelector.GetTarget(-1, TargetSelector.DamageType.Physical);
					if (target != null)
					{
						return target;
					}
				}

				/*Killable Minion*/
				//if (ActiveMode == OrbwalkingMode.LaneClear || ActiveMode == OrbwalkingMode.Mixed ||
				//	ActiveMode == OrbwalkingMode.LastHit || Program.ComboMenu.Item("MinionOrbwalking").GetValue<bool>())
				//{
				//	var MinionList =
				//		ObjectManager.Get<Obj_AI_Minion>()
				//			.Where(
				//				minion =>
				//					minion.IsValidTarget() && InAutoAttackRange(minion) &&
				//					minion.Health <
				//					2 *
				//					(ObjectManager.Player.BaseAttackDamage + ObjectManager.Player.FlatPhysicalDamageMod));

				//	foreach (var minion in MinionList)
				//	{
				//		var t = (int)(Player.AttackCastDelay * 1000) - 100 + Game.Ping / 2 +
				//				   1000 * (int)Player.Distance(minion) / (int)GetMyProjectileSpeed();
				//		var predHealth = HealthPrediction.GetHealthPrediction(minion, t, FarmDelay);

				//		if (minion.Team != GameObjectTeam.Neutral && MinionManager.IsMinion(minion, true))
				//		{
				//			if (predHealth < 0 && minion.Health > 20) //#TODO
				//			{
				//				FireOnNonKillableMinion(minion);
				//			}

				//			if (predHealth > 0 && predHealth <= (Player.GetAutoAttackDamage(minion, true)))
				//			{
				//				return minion;
				//			}
				//		}
				//	}
				//}

				//Forced target
				if (_forcedTarget.IsValidTarget() && InAutoAttackRange(_forcedTarget))
				{
					return _forcedTarget;
				}

				/* turrets / inhibitors / nexus */
				if (ActiveMode == OrbwalkingMode.LaneClear)
				{
					/* turrets */
					foreach (var turret in
						ObjectManager.Get<Obj_AI_Turret>().Where(t => t.IsValidTarget() && InAutoAttackRange(t)))
					{
						return turret;
					}

					/* inhibitor */
					foreach (var turret in
						ObjectManager.Get<Obj_BarracksDampener>().Where(t => t.IsValidTarget() && InAutoAttackRange(t)))
					{
						return turret;
					}

					/* nexus */
					foreach (var nexus in
						ObjectManager.Get<Obj_HQ>().Where(t => t.IsValidTarget() && InAutoAttackRange(t)))
					{
						return nexus;
					}
				}

				/*Champions*/
				if (ActiveMode != OrbwalkingMode.LastHit)
				{
					var target = TargetSelector.GetTarget(-1,TargetSelector.DamageType.Physical);
					if (target.IsValidTarget())
					{
						if (target.IsMelee && Items.HasItem((int)ItemId.Thornmail, target) && target.HealthPercent > Player.HealthPercent && Player.HealthPercent < 20)
						{
							return
								MinionManager.GetMinions(Player.ServerPosition, Orbwalking.GetRealAutoAttackRange(null))
									.OrderBy(m => m.Armor)
									.FirstOrDefault() ?? target;
						}
						else
						{
							return target;
						}
					}
				}

				if (ActiveMode == OrbwalkingMode.Combo && Items.HasItem((int)ItemId.The_Bloodthirster, Player))
				{
					var minion =
						MinionManager.GetMinions(Player.ServerPosition, GetRealAutoAttackRange(null))
							.OrderBy(m => m.Armor).FirstOrDefault();
					if (Player.CountEnemiesInRange(600) == 0 && Player.HealthPercent < 60 && minion != null)
					{
						return minion;
					}
				}

				/*Jungle minions*/
				if (ActiveMode == OrbwalkingMode.LaneClear || ActiveMode == OrbwalkingMode.Mixed)
				{
					result =
						ObjectManager.Get<Obj_AI_Minion>()
							.Where(
								mob =>
									mob.IsValidTarget() && mob.Team == GameObjectTeam.Neutral && InAutoAttackRange(mob) && mob.CharData.BaseSkinName != "gangplankbarrel")
							.MaxOrDefault(mob => mob.MaxHealth);
					if (result != null)
					{
						return result;
					}
				}

				/*Lane Clear minions*/
			//	if (ActiveMode == OrbwalkingMode.LaneClear || (ActiveMode == OrbwalkingMode.Combo && Program.ComboMenu.Item("MinionOrbwalking").GetValue<bool>()))
			//	{
			//		if (!ShouldWait())
			//		{
			//			if (_prevMinion.IsValidTarget() && InAutoAttackRange(_prevMinion))
			//			{
			//				var predHealth = HealthPrediction.LaneClearHealthPrediction(
			//					_prevMinion, (int)((Player.AttackDelay * 1000) * LaneClearWaitTimeMod), FarmDelay);
			//				if (predHealth >= 2 * Player.GetAutoAttackDamage(_prevMinion) ||
			//					Math.Abs(predHealth - _prevMinion.Health) < float.Epsilon)
			//				{
			//					return _prevMinion;
			//				}
			//			}

			//			result = (from minion in
			//						  ObjectManager.Get<Obj_AI_Minion>()
			//							  .Where(minion => minion.IsValidTarget() && InAutoAttackRange(minion) && minion.CharData.BaseSkinName != "gangplankbarrel")
			//					  let predHealth =
			//						  HealthPrediction.LaneClearHealthPrediction(
			//							  minion, (int)((Player.AttackDelay * 1000) * LaneClearWaitTimeMod), FarmDelay)
			//					  where
			//						  predHealth >= 2 * Player.GetAutoAttackDamage(minion) ||
			//						  Math.Abs(predHealth - minion.Health) < float.Epsilon
			//					  select minion).MaxOrDefault(m => m.Health);

			//			if (result != null)
			//			{
			//				_prevMinion = (Obj_AI_Minion)result;
			//			}
			//		}
			//	}

				return result;
			}

			private void OnUpdate(EventArgs args) {
				try
				{
					if (ActiveMode == OrbwalkingMode.None)
					{
						return;
					}

					//Prevent canceling important spells
					if (Player.IsCastingInterruptableSpell(true))
					{
						return;
					}

					var target = GetTarget();
					var objaihero_target = target as Obj_AI_Hero;
					Orbwalk(
						target, objaihero_target.IsValidTarget() ? objaihero_target.GetKitePos() : Game.CursorPos,
						_config.Item("ExtraWindup").GetValue<Slider>().Value,
						_config.Item("HoldPosRadius").GetValue<Slider>().Value);
				}
				catch (Exception e)
				{
					Console.WriteLine(e);
				}
			}

			private void DrawingOnOnDraw(EventArgs args) {
				if (Program.DrawingsMenu.Item("streamingmode").GetValue<bool>())
				{
					Program.DrawingsMenu.Item("enemycccounter").Permashow(false);
					Program.DrawingsMenu.Item("enemycounter").Permashow(false);
					return;
				}
				if (!_config.Item("AACircle2").GetValue<Circle>().Active
					&& _config.Item("AACircle3").GetValue<Circle>().Active)
				{
					var myTarget = GetTarget();
					if (myTarget != null)
					{
						Render.Circle.DrawCircle(myTarget.Position, myTarget.IsValid<Obj_AI_Hero>() ? GetRealAutoAttackRange(myTarget) : 75,
							_config.Item("AACircle3").GetValue<Circle>().Color);
					}
				}

				if (_config.Item("AACircle").GetValue<Circle>().Active)
				{
					Render.Circle.DrawCircle(
						Player.Position, GetRealAutoAttackRange(null) + 65,
						_config.Item("AACircle").GetValue<Circle>().Color);
				}

				if (_config.Item("AACircle2").GetValue<Circle>().Active)
				{
					foreach (var target in
						HeroManager.Enemies.FindAll(target => target.IsValidTarget(1175)))
					{
						Render.Circle.DrawCircle(
							target.Position, GetRealAutoAttackRange(target) + 65,
							_config.Item("AACircle2").GetValue<Circle>().Color);
					}
				}

				if (_config.Item("HoldZone").GetValue<Circle>().Active)
				{
					Render.Circle.DrawCircle(
						Player.Position, _config.Item("HoldPosRadius").GetValue<Slider>().Value,
						_config.Item("HoldZone").GetValue<Circle>().Color);
				}

			}
		}
	}
}
